/*
   Copyright (C) 2009 Xizhi Zhu.  All Rights Reserved.

   Redistribution and use in source and binary forms, with or without
   modification, are permitted provided that the following conditions are met:

   1. Redistributions of source code must retain the above copyright notice,
   this list of conditions and the following disclaimer.
   2. Redistributions in binary form must reproduce the above copyright notice,
   this list of conditions and the following disclaimer in the documentation
   and/or other materials provided with the distribution.
   3. The name of the author may not be used to endorse or promote products
   derived from this software without specific prior written permission.

   THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
   IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
   IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
   PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
   OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
   WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
   OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
   ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

#ifndef __p2p_app_h__
#define __p2p_app_h__

#include <vector>
#include "real-app.h"
#include "p2p-tracker.h"

class ConnectionCheckTimer;
struct PeerInfo;
struct ChunkInfo;

class P2PApp: public RealApplication
{
    friend class ConnectionCheckTimer;

public:
    P2PApp(Node* node);
    virtual ~P2PApp();

    virtual void recv(ADU* packet, nsaddr_t src);

protected:
    virtual int command(int argc, const char*const* argv);

private:
    P2PTracker* tracker_;

    std::vector<PeerInfo> server_list_;
    std::vector<PeerInfo> peer_list_;

    ConnectionCheckTimer* connectionCheckTimer_;

    std::vector<ChunkInfo> chunks_;

    // we tried to connected to known peers in the last period if it's true
    bool tried_;

    // register to the tracker
    void start();

    // unregister itself to the tracker
    void stop();

    // update the time a packet is received from this node
    void updateTime(nsaddr_t src);

    // check connection and connect to peers when necessary
    void checkConnection();

    // delete timeouted nodes
    void deleteOldNode();

    // check if the connection speed is fast enough
    bool enoughConnectionSpeed() const;

    // request chunk list of a node
    void chunkListRequest();

    // called when the chunk list is requested
    void handleChunkListRequest(P2PPacket* packet);

    // called when the chunk list is received from src
    void handleChunkListReply(P2PPacket* packet);

    // request chunks
    void chunkRequest();

    // called when a chunk is requested
    void handleChunkRequest(P2PPacket* packet);

    // called when a chunk is received
    void handleChunkReply(P2PPacket* packet);

    // put the received node list into local list
    void addNodeToList(P2PPacket* packet);
};

struct PeerInfo
{
    nsaddr_t id_;
    bool connected_;
    double updated_;    // last time a packet is received from this node
};

struct ChunkInfo
{
    int available_;
    std::vector<nsaddr_t> who_has_;
};

class ConnectionCheckTimer: public TimerHandler
{
public:
    ConnectionCheckTimer(P2PApp* app);
    virtual void expire(Event *);

private:
    P2PApp* app_;
};

#endif // __p2p_app_h__

